package cn.maihe.elg.operation.supports.invoice.nuonuo;

import cn.maihe.elg.operation.config.ZtAccountInfo;
import cn.maihe.elg.operation.model.enums.AcceptOrderStatus;
import cn.maihe.elg.operation.model.enums.CenterNoEnum;
import cn.maihe.elg.operation.model.enums.InvoiceStatusEnum;
import cn.maihe.elg.operation.model.vo.order.AcceptOrderStatusAuditVO;
import cn.maihe.elg.operation.repository.entity.AcceptOrderInfoDO;
import cn.maihe.elg.operation.repository.entity.BidCustomerDO;
import cn.maihe.elg.operation.repository.entity.InvoiceInfoDO;
import cn.maihe.elg.operation.repository.entity.ProjectInfoDO;
import cn.maihe.elg.operation.repository.entity.SellerInfoDO;
import cn.maihe.elg.operation.repository.entity.SellerInfoDOCondition;
import cn.maihe.elg.operation.repository.entity.SpdBankNotice;
import cn.maihe.elg.operation.service.business.BidCustomerService;
import cn.maihe.elg.operation.service.business.ExchangeCenterService;
import cn.maihe.elg.operation.service.business.ProjectInfoService;
import cn.maihe.elg.operation.service.invoice.InvoiceInfoService;
import cn.maihe.elg.operation.service.invoice.SellerInfoService;
import cn.maihe.elg.operation.service.order.AcceptOrderInfoService;
import cn.maihe.elg.operation.service.order.SpdBankNoticeService;
import cn.maihe.elg.operation.utils.CreateGuaranteeUtil;
import cn.maihe.elg.operation.utils.DateUtil;
import cn.maihe.elg.operation.utils.ElgLogger;
import com.alibaba.fastjson.JSONObject;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import nuonuo.open.sdk.NNOpenSDK;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.file.Path;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

/**
 * @Description
 * @Author caixh
 * @Date 2021/4/26.
 */

@Api(value = "发票授权回调", tags = "发票授权回调")
@Controller
@RequestMapping("/invoice")
@Slf4j
public class InvoiceNuonuoCallback {
    @Autowired
    private InvoiceNuonuoConfig invoiceNuonuoConfig;
    @Resource
    private SellerInfoService sellerInfoService;
    @Resource
    private InvoiceInfoService invoiceInfoService;
    @Resource
    private InvoiceDownLoadHelper invoiceDownLoadHelper;
    @Resource
    private AcceptOrderInfoService acceptOrderInfoService;
    @Resource
    private SpdBankNoticeService spdBankNoticeService;
    @Resource
    private ZtAccountInfo ztAccountInfo;
    @Resource
    private ProjectInfoService projectInfoService;
    @Resource
    private BidCustomerService bidCustomerService;
    @Resource
    private InvoiceHelper invoiceHelper;
    @Resource
    private ExchangeCenterService exchangeCenterService;

    @Value("${cn.maihe.elg.operation.schedule.payStatusCheckTimes:1000}")
    private int checkTimes;

    @Value("${cn.maihe.elg.operation.invoice-callback-auto-guarantee:false}")
    private Boolean invoiceCallbackAutoGuarantee;

    @ApiOperation(value = "授权回调", notes = "授权回调")
    @RequestMapping(value = "/nuonuo/authCallback", method = RequestMethod.GET)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "code", value = "临时授权码", dataType = "String", paramType = "query", required = true),
            @ApiImplicitParam(name = "taxnum", value = "授权商户税号", dataType = "String", paramType = "query", required = true),
            @ApiImplicitParam(name = "state", value = "自定义参数", dataType = "String", paramType = "query")
    })
    public String authCallback(@RequestParam(value = "code") String code, @RequestParam(value = "taxnum") String taxnum, @RequestParam(value = "state") String state) {

        ElgLogger.debug(log, l -> l.debug("授权回调：code:{},taxnum:{},state:{}", code, taxnum, state));

        SellerInfoDO sellerInfoDO = sellerInfoService.selectOne(SellerInfoDOCondition.builder().andSellerCreditCodeEq(taxnum).build());
        if (sellerInfoDO == null) {
            try {
                return "redirect:" + invoiceNuonuoConfig.getAuthReturnBaseUrl() + "#/authError?msg=" + URLEncoder.encode("统一信用号不正确", "UTF-8");
            } catch (UnsupportedEncodingException e) {
                return "redirect:" + invoiceNuonuoConfig.getAuthReturnBaseUrl() + "#/authError?msg=error";
            }
        }

        String json = NNOpenSDK.getIntance().getISVToken(invoiceNuonuoConfig.getAppKey(), invoiceNuonuoConfig.getAppSecret(),
                code, taxnum, invoiceNuonuoConfig.getRedirectUri());
        ElgLogger.debug(log, l -> l.debug("授权回调：{}", json));

        JSONObject tokenJson = JSONObject.parseObject(json);
        if (tokenJson.containsKey("access_token")) {
            String token = tokenJson.getString("access_token");
            String refreshToken = tokenJson.getString("refresh_token");
            String userId = tokenJson.getString("userId");
            sellerInfoDO.setToken(token);
            sellerInfoDO.setRefreshToken(refreshToken);
            sellerInfoService.updateById(sellerInfoDO);
            return "redirect:" + invoiceNuonuoConfig.getAuthReturnBaseUrl() + "#/authSuccess";
        } else {
            ElgLogger.error(log, l -> l.error("授权回调：{}", json));
            try {
                return "redirect:" + invoiceNuonuoConfig.getAuthReturnBaseUrl() + "#/authError?msg=" + URLEncoder.encode("获取授权码失败，请重新授权", "UTF-8");
            } catch (UnsupportedEncodingException e) {
                return "redirect:" + invoiceNuonuoConfig.getAuthReturnBaseUrl() + "#/authError?msg=error";
            }
        }

    }

    @ApiOperation(value = "开票回调", notes = "开票回调")
    @RequestMapping(value = "/nuonuo/invoiceCallback", method = RequestMethod.POST)
    @ResponseBody
    public JSONObject invoiceCallback(@RequestParam(value = "operater", required = true) String operater,
                                      @RequestParam("content") String content,
                                      @RequestParam("orderno") String orderno,
                                      Map<String, Object> map) {
        JSONObject result = new JSONObject();
        result.put("status", "9999");
        if (StringUtils.isEmpty(operater)) {
            ElgLogger.error(log, l -> l.error("开票回调：{},{},{}", operater, content, orderno));
            result.put("message", "接口标识为空");
        } else if (StringUtils.isEmpty(content)) {
            ElgLogger.error(log, l -> l.error("开票回调：{},{},{}", operater, content, orderno));
            result.put("message", "开票信息为空");
        } else if (StringUtils.isEmpty(orderno)) {
            ElgLogger.error(log, l -> l.error("开票回调：{},{},{}", operater, content, orderno));
            result.put("message", "订单编号为空");
        } else {
            if (operater.equals("callback")) {
                InvoiceInfoDO invoiceInfoDO = invoiceInfoService.selectById(Long.parseLong(orderno));
                if (invoiceInfoDO == null) {
                    ElgLogger.error(log, l -> l.error("开票回调：{},{},{}, {}", operater, content, orderno, "订单编号对应订单不存在"));
                    result.put("message", "订单编号对应订单不存在");
                } else {
                    JSONObject invoiceJO = JSONObject.parseObject(content);
                    String pdfUrl = invoiceJO.getString("c_url");
                    String invoiceNo = invoiceJO.getString("c_fphm");
                    if (StringUtils.isBlank(pdfUrl)||StringUtils.isBlank(invoiceNo)) {
                        ElgLogger.error(log, l -> l.error("开票回调：{},{},{}, {}", operater, content, orderno, "c_url即发票pdf下载地址或c_fphm发票号为空"));
                    } else {
                        invoiceInfoDO.setStatus(InvoiceStatusEnum.TODOWNLOAD.getValue());
                        invoiceInfoDO.setInvoiceImg(pdfUrl);
                        invoiceInfoDO.setPdfUrl(pdfUrl);
                        invoiceInfoDO.setSerialNo(invoiceJO.getString("c_fpqqlsh"));
                        invoiceInfoDO.setInvoiceNo(invoiceJO.getString("c_fphm"));
                        invoiceInfoDO.setInvoiceCode(invoiceJO.getString("c_fpdm"));
                        invoiceInfoService.updateById(invoiceInfoDO);

                        CompletableFuture.runAsync(()->{
                            String acceptOrderNo = invoiceInfoDO.getAcceptOrderNos();
                            try {
                                ElgLogger.info(log, l -> l.info("acceptOrderNo:{} >> 发票下载：{}", acceptOrderNo,pdfUrl));
                                Path invoicePdf = invoiceDownLoadHelper.downloadInvoice(invoiceInfoDO.getPdfUrl());
                                ElgLogger.info(log, l -> l.info("acceptOrderNo={} << 发票下载成功：{}", acceptOrderNo, invoicePdf.toAbsolutePath().toString()));
                                invoiceDownLoadHelper.savePdfAndUpdateInvoice(invoicePdf, invoiceInfoDO);
                                invoiceInfoService.updateById(invoiceInfoDO);
                            } catch (Exception e) {
                                ElgLogger.error(log, l -> l.error("acceptOrderNo={} << 发票下载失败:{}", acceptOrderNo, e.getMessage(), e));
                            }

                            try {
                                AcceptOrderInfoDO orderInfo = acceptOrderInfoService.getByAcceptOrderNo(acceptOrderNo);
                                AcceptOrderStatus status = AcceptOrderStatus.resolve(orderInfo.getStatus().intValue());

                                CenterNoEnum centerNoEnum = exchangeCenterService.getCenterNoEnumByAcceptOrderNo(acceptOrderNo);
                                if(CreateGuaranteeUtil.isGuoGu(centerNoEnum) || CreateGuaranteeUtil.isMeiShan(centerNoEnum)){
                                    ElgLogger.info(log, l -> l.info("invoiceCallback invoiceResultNotify >> acceptOrderNo：{}", acceptOrderNo));
                                    invoiceHelper.invoiceResultNotify(acceptOrderNo);
                                }

                                if (invoiceCallbackAutoGuarantee && status.equals(AcceptOrderStatus.WAIT_PAY_CONFIRM) && orderInfo.getCheckTimes() > checkTimes) {
                                    BidCustomerDO bidCustomer = bidCustomerService.selectById(orderInfo.getBidCustomerId());
                                    ProjectInfoDO projectInfo = projectInfoService.selectById(orderInfo.getProjectId());
                                    String payerAcctNo = bidCustomer.getBankCardNum().replace(" ", "");
                                    String payeeAcctNo = ztAccountInfo.getAccNo();
                                    Long guaranteeFee = orderInfo.getGuaranteeFee();
                                    //String sectionCode = projectInfo.getSectionCode();
                                    String projectCode = projectInfo.getProjectCode();
                                    SpdBankNotice spdBankNotice = spdBankNoticeService.selectMatchPayInfoAndSectionCode(payerAcctNo, payeeAcctNo, guaranteeFee, projectCode, orderInfo);
                                    if (spdBankNotice != null && projectInfo.getTemplateId() != null) {
                                        orderInfo.setTemplateId(projectInfo.getTemplateId());
                                        doConfirmPayStatus(orderInfo, spdBankNotice);
                                    }
                                }
                            } catch (Exception e) {
                                ElgLogger.error(log, l -> l.error("acceptOrderNo:{} >> 开票回调自动确认已转账处理异常:{}", acceptOrderNo, e.getMessage(), e));
                            }
                        });
                    }
                    result.put("status", "0000");
                    ElgLogger.debug(log, l -> l.debug("开票回调：{},{},{}", operater, content, orderno));
                    result.put("message", "同步成功");

                }
            } else {
                ElgLogger.error(log, l -> l.error("开票回调：{},{},{},{}", operater, content, orderno, "接口标识非回调接口"));
                result.put("message", "接口标识非回调接口");
            }
        }
        return result;

    }

    @Transactional(rollbackFor = Exception.class)
    public SpdBankNotice doConfirmPayStatus(AcceptOrderInfoDO orderInfo, SpdBankNotice spdBankNotice) {

        AcceptOrderStatusAuditVO auditVO = new AcceptOrderStatusAuditVO();
        auditVO.setId(orderInfo.getId());
        auditVO.setStatus(orderInfo.getStatus());
        auditVO.setAuditStatus(1);
        auditVO.setPayTime(DateUtil.formatDateStr(spdBankNotice.getTransDate(), DateUtil.FORMAT_TRADEDATE, DateUtil.FORMAT_DATE));
        auditVO.setTemplateId(orderInfo.getTemplateId());
        auditVO.setAuditRemark("开票回调 >> 系统检测到转账已到账，自动审核通过");
        ElgLogger.info(log, l -> l.info("开票回调 >> 核心交易流水号:{} << 母账户账号[{}],来账账号[{}],交易金额[{}元],附言[{}] 检测识别为受理订单号[{}]保函编号[{}]的转账记录并做自动审核通过",
                spdBankNotice.getCoreSerNo(), spdBankNotice.getParentAcctNo(), spdBankNotice.getAcctNo(), spdBankNotice.getTransAmt(),
                spdBankNotice.getAttach(), orderInfo.getAcceptOrderNo(), orderInfo.getGuaranteeNo()));

        //自动审核
        acceptOrderInfoService.auditWaitPayConfirm(auditVO);

        //更新入金通知记录
        spdBankNotice.setAcceptOrderNo(orderInfo.getAcceptOrderNo());
        spdBankNoticeService.updateById(spdBankNotice);
        return spdBankNotice;
    }

}
